package com.leecreate.tutool.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.leecreate.tutool.domain.hardpull.*;
import com.leecreate.tutool.service.ApplicationService;
import com.leecreate.tutool.service.HardPullService;
import com.leecreate.tutool.utils.DateUtils;
import com.leecreate.tutool.utils.StringUtils;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service("hardPullService")
public class HardPullServiceImpl implements HardPullService {
    @Value("${tu.baseURL}")
    private String baseURL;
    @Value("${tu.userName}")
    private String userName;
    @Value("${tu.password}")
    private String password;
    @Value("${tu.solutionSetId}")
    private int solutionSetId;

    @Value("${tu.TelephoneNumber}")
    private String TelephoneNumber;

    @Value("${tu.TelephoneCountryCode}")
    private String TelephoneCountryCode;

    @Value("${tu.TelephoneAreaCode}")
    private String TelephoneAreaCode;

    @Value("${tu.TelephoneExtension}")
    private String TelephoneExtension;

    @Value("${tu.PostalCode}")
    private String PostalCode;

    @Value("${tu.EmailAddress}")
    private String EmailAddress;

    @Value("${tu.ServiceType}")
    private String ServiceType;


    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private ApplicationService applicationService;


    public String getToken() throws UnirestException {
        Unirest.setTimeouts(0, 0);
        HttpResponse<String> response = Unirest.post(baseURL + "/Token").header("Content-Type", "application/x-www-form-urlencoded").field("grant_type", "password").field("username", userName).field("password", password).asString();
        String body = response.getBody();
        Map map = JSON.parseObject(body, Map.class);
        String accessToken = (String) map.get("access_token");
        redisTemplate.opsForValue().set("tu:access_token", accessToken, 5 * 60, TimeUnit.SECONDS);
        return accessToken;
    }

    private HardPullBean fillValue(HardPullVo hardPullVo) {
        HardPullBean hardPullBean = new HardPullBean();

        Fields fields = new Fields();
        fields.setServiceType(ServiceType);

        Applicants_IO applicantsIo = new Applicants_IO();

        List<Applicant> applicantList = new ArrayList<>();
        Applicant applicant = new Applicant();
        applicant.setApplicantLastName(hardPullVo.getApplicantLastName());
        applicant.setApplicantFirstName(hardPullVo.getApplicantFirstName());
        applicant.setDateOfBirth(hardPullVo.getDateOfBirth());
        applicant.setDOBSymbols("");


        //e-mail
        EmailAddresses emailAddresses = new EmailAddresses();

        List<EmailAddress> emailAddressList = new ArrayList<>();

        EmailAddress emailAddress = new EmailAddress();
        emailAddress.setValue(EmailAddress);
        emailAddress.setType("P");
        emailAddress.setCategory("P");

        emailAddressList.add(emailAddress);

        emailAddresses.setEmailAddress(emailAddressList);

        applicant.setEmailAddresses(emailAddresses);

        //telephone
        Telephones telephones = new Telephones();

        List<Telephone> telephoneList = new ArrayList<>();

        Telephone telephone = new Telephone();

        telephone.setTelephoneType("P");
        telephone.setTelephoneCategory("M");
        telephone.setTelephoneCountryCode(TelephoneCountryCode);
        telephone.setTelephoneNumber(TelephoneNumber);
        telephone.setTelephoneAreaCode(TelephoneAreaCode);
        telephone.setTelephoneExtension(TelephoneExtension);
        telephone.setMFormat("S");

        telephoneList.add(telephone);

        telephones.setTelephone(telephoneList);

        applicant.setTelephones(telephones);


        //Addresses
        Addresses addresses = new Addresses();

        List<Address> addressList = new ArrayList<>();

        Address address = new Address();

        address.setAddressType("R");
        address.setAddressLine1(hardPullVo.getAddressLine1());
        address.setAddressLine2(hardPullVo.getAddressLine2());
        address.setAddressLine3(hardPullVo.getAddressLine3());
        address.setAddressLine4(hardPullVo.getAddressLine4());
        address.setAddressLine5("");
        address.setPostalCode(PostalCode);

        addressList.add(address);

        addresses.setAddress(addressList);

        applicant.setAddresses(addresses);


        //Identifiers
        Identifiers identifiers = new Identifiers();

        List<Identifier> identifierList = new ArrayList<>();

        Identifier identifier = new Identifier();

        identifier.setIdType("ID");
        identifier.setIdNumber(hardPullVo.getIdNumber());
        identifier.setIdIssuingCountry("HKG");
        identifier.setIdDocumentName("");
        identifier.setIDExpireDate("");

        identifierList.add(identifier);

        identifiers.setIdentifier(identifierList);

        applicant.setIdentifiers(identifiers);


        applicantList.add(applicant);
        applicantsIo.setApplicant(applicantList);


        fields.setApplicants_IO(applicantsIo);


        ApplicationData_IO applicationDataIo = new ApplicationData_IO();

        applicationDataIo.setApplicationRequestDate(DateUtils.dateToNoSplashHKString(new Date()));
        applicationDataIo.setCurrencyCode("HKD");
        applicationDataIo.setLoanAmount(hardPullVo.getLoanAmount());
        applicationDataIo.setProduct(hardPullVo.getProduct());

        fields.setApplicationData_IO(applicationDataIo);


        hardPullBean.setFields(fields);

        return hardPullBean;

    }

    @Override
    public HardPullDto bureauHardPull(HardPullVo hardPullVo) {
        HardPullDto hardPullDto = new HardPullDto();
        try {
            int applicationId = 0;
            String accessToken = "";
            accessToken = (String) redisTemplate.opsForValue().get("tu:access_token");
            if (StringUtils.isEmpty(accessToken)) {
                accessToken = getToken();
                applicationId = applicationService.createApplication(accessToken, solutionSetId, baseURL);
                redisTemplate.opsForValue().set("tu:application_id", applicationId);
            } else {
                applicationId = (int) redisTemplate.opsForValue().get("tu:application_id");
            }
            HardPullBean hardPullBean = fillValue(hardPullVo);
            String body = JSONUtil.toJsonStr(hardPullBean);
            Unirest.setTimeouts(0, 0);
            HttpResponse<String> response = Unirest.post(baseURL + "/applications/" + applicationId + "/queues/TSO_ServiceInput").header("Content-Type", "application/json").header("Authorization", "Bearer " + accessToken).body(body).asString();
            if (response != null) {
                body = response.getBody();
                Map map = JSON.parseObject(body, Map.class);
                map = (Map) map.get("Fields");
                map = (Map) map.get("Applicants_IO");
                JSONArray array = (JSONArray) map.get("Applicant");
                for (int i = 0; i < array.size(); i++) {
                    map = (Map) array.get(i);
                    Map mapStatus = (Map) map.get("DSBureauHardPullStatus");
                    if (mapStatus != null) {
                        boolean isSuccess = (boolean) mapStatus.get("IsSuccess");
                        if (isSuccess) {
                            map = (Map) map.get("DSBureauHardPullData");
                            map = (Map) map.get("Response");
                            map = (Map) map.get("Data");
                            body = (String) map.get("HumanReadableReport");
                            hardPullDto.setBody(body);
                            hardPullDto.setSuccess(true);
                        } else {
                            String errorMessage = (String) mapStatus.get("ErrorMessage");
                            hardPullDto.setError(errorMessage);
                            hardPullDto.setSuccess(false);
                        }
                        break;
                    }
                }
            }
        } catch (Exception e) {
            hardPullDto.setError(e.toString());
            hardPullDto.setSuccess(false);
        }
        return hardPullDto;
    }
}
